package cgl.narada.samples.security;

/**
 * This class is adapted from cgl.narada.samples.rtp.NBRTPTransmitter.
 * It uses NBMediaConnector to transmit stream.
 *
 * @author Hasan Bulut  - hbulut@indiana.edu
 * Community Grids Lab., Indiana University
 * @version 1.0
 */
import java.awt.Dimension;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.security.PrivateKey;
import java.util.Properties;

import javax.media.CaptureDeviceInfo;
import javax.media.CaptureDeviceManager;
import javax.media.Format;
import javax.media.MediaLocator;
import javax.media.format.VideoFormat;
import javax.media.protocol.ContentDescriptor;
import javax.media.protocol.DataSource;
import javax.media.rtp.RTPConnector;
import javax.media.rtp.RTPManager;
import javax.media.rtp.SendStream;

import cgl.narada.samples.rtp.MediaCapturer;
import cgl.narada.service.ServiceException;
import cgl.narada.service.client.EventProducer;
import cgl.narada.service.security.kmc.messages.SecureTopicKeyResponse;

public class NBMediaTransmitter {

    private RTPManager rtpManager = null;
    private DataSource dataSource = null;
    private RTPConnector connector = null;

    public NBMediaTransmitter(RTPConnector connector) {
        this.connector = connector;
    }

    public void setDataSource(DataSource ds) {

        if (ds == null) {
            System.out.println("DataSource is null.");
            return;
        }

        if (this.dataSource != null) {
            System.out.println("datasource is already set.");
            return;
        }
        this.dataSource = ds;
    }

    public void close() {

        if (dataSource != null) {
            dataSource.disconnect();
        }

        if (rtpManager != null) {
            rtpManager.removeTargets("Session ended.");
            rtpManager.dispose();
            rtpManager = null;
        }
    }

    public String start() {
        try {
            rtpManager = RTPManager.newInstance();
            System.out.println("Before initializing RTP Manager");
            rtpManager.initialize(connector);
            System.out.println("After initializing RTP Manager");
            SendStream sendStream = rtpManager.createSendStream(dataSource, 0);
            sendStream.start();
            System.out.println("Started transmitting data with the ssrc: "
                    + sendStream.getSSRC());
        } catch (javax.media.format.UnsupportedFormatException e) {
            System.out
                    .println(this.getClass().getName()
                            + "  Exception while trying to initialize rtp manager. The message is: "
                            + e.getMessage());
            System.out.println(this.getClass().getName()
                    + "  the failed exception is: " + e.getFailedFormat());
            return e.getMessage();
        } catch (Exception e) {
            return e.getMessage();
        }
        return null;
    }

    public static void main(String args[]) throws Exception {
        // if ((args.length < 4) || (args.length > 5)) {
        // printUsage();
        // return;
        //        }

        String brokerIP = args[0];
        int brokerPort = Integer.parseInt(args[1]);
        int topicNumber = Integer.parseInt(args[2]);
        String commType = args[3];

        boolean formath263 = true;
        System.out.println("input size: " + args.length);
        if (args.length == 5) {
            formath263 = false;
        }

        // default values
        String keyAlg = "AES";
        int keySize = 128, timeout1 = 5, timeout2 = 2;
        String sig = "SHA1withRSA", mode = "CBC", padding = "PKCS7Padding";

        if (args.length > 5)
            keyAlg = args[5];
        if (args.length > 6)
            keySize = Integer.parseInt(args[6]);
        if (args.length > 7)
            timeout1 = Integer.parseInt(args[7]);
        if (args.length > 8)
            timeout2 = Integer.parseInt(args[8]);
        if (args.length > 9)
            sig = args[9];
        if (args.length > 10)
            mode = args[10];
        if (args.length > 11)
            padding = args[11];
        
        

        NBMediaConnector connector = new NBMediaConnector(brokerIP, brokerPort,
                2, topicNumber);

        String control = connector.getControlTopic();
        String data = connector.getDataTopic();

        System.out.println("Generating topics and Security Tokens");

        SecureTopicsKeyGenerator stkGen = new SecureTopicsKeyGenerator(data,
                control, "c1", brokerIP, "" + brokerPort, commType);

        stkGen.generateTopics(keyAlg, keySize, timeout1, timeout2);
        connector.setEncryptedDataTopicUUID(stkGen.topicUUIDData);
        connector.setEncryptedControlTopicUUID(stkGen.topicUUIDControl);

        System.out.println("DONE .... ! Press a key to continue...");
        System.in.read();

        MediaLocator ml = getMediaLocator();
        ContentDescriptor cd = new ContentDescriptor(ContentDescriptor.RAW_RTP);

        // Valid sizes
        // 176x144, 352x288,

        VideoFormat vf1 = new VideoFormat(VideoFormat.H261_RTP, new Dimension(
                176, 144), Format.NOT_SPECIFIED, null, Format.NOT_SPECIFIED);
        // VideoFormat vf1 = new VideoFormat(VideoFormat.H261_RTP);
        VideoFormat vf2 = new VideoFormat(VideoFormat.H263_RTP);
        VideoFormat vf = null;
        if (formath263) {
            vf = vf2;
        } else {
            vf = vf1;
        }
        // MediaCapturer mc = new MediaCapturer(ml, cd, format);
        MediaCapturer mc = new MediaCapturer(ml, cd, vf);
        // construct a clone for the datasource so that we can both play and
        // transmit it
        DataSource dataSource = mc.getDataSource();
        // dataSource =
        // javax.media.Manager.createCloneableDataSource(dataSource);
        // DataSource clonedDataSource =
        // ((SourceCloneable)dataSource).createClone();

        // play the video
        // new PlayerWindow(dataSource);

        // send the video
        Properties props = new Properties();
        props.put("hostname", brokerIP);
        props.put("portnum", args[1]);

        try {
            connector.initializeBrokerCommunications(props, commType);
            connector.initializeTransmitter(sig, mode, padding, stkGen.topicUUIDData,
                    stkGen.stkData, stkGen.topicUUIDControl, stkGen.stkControl,
                    stkGen.c_priv);
        } catch (ServiceException ex) {
            ex.printStackTrace();
        }
        NBMediaTransmitter ct = new NBMediaTransmitter(connector);
        ct.setDataSource(dataSource);
        String result = ct.start();
        if (result != null) {
            System.err
                    .println("Failed to initialize the transmitter. The message is: "
                            + result);
        } else {
            System.err.println("  - Started transmitting data to the topic: "
                    + topicNumber + " at the broker " + brokerIP + ":"
                    + brokerPort);
        }

        // start the receiver
        // NBMediaReceiver.startReceiver(connector);

        // wait indefinetely

        try {
            BufferedReader commandLine = new BufferedReader(
                    new InputStreamReader(System.in));

            while (true) {
                String s = commandLine.readLine();
                if (s == null) {
                    System.out.println("Specified command is null! Exiting.");
                    ct.close();
                    break;
                }
                if (s.equals("h")) {
                    System.out
                            .println("\n\nComands for the NBMediaTransmitter:");
                    System.out
                            .println("s\t\t\t Stops the trasmitter and exits !!!");
                    System.out.println("p\t\t\t Pauses the transmitter");
                    System.out
                            .println("r\t\t\t Restarts the transmitter after pause");
                }
                if (s.equals("s")) {
                    ct.close();
                }
                if (s.equals("p")) {
                    // connector.setPublishEnabled(false);
                    dataSource.stop();
                }
                if (s.equals("r")) {
                    // connector.setPublishEnabled(true);
                    dataSource.start();
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }

    } // end of main

    public static void printUsage() {
        System.out
                .println("Usage: java cgl.narada.samples.rtp.Transmitter  <Broker IP>   <Broker Port>   <Topic Number>");
    }

    /**
     * get a MediaLocator from a capture device for video
     */
    public static MediaLocator getMediaLocator() {
        VideoFormat videoFormat = new VideoFormat(VideoFormat.YUV);
        java.util.Vector deviceList = CaptureDeviceManager
                .getDeviceList(videoFormat);
        MediaLocator ml = null;
        if (deviceList.size() == 0) {
            System.out
                    .println("There is no video device on the computer or You did not run JMFRegistry");
            System.out
                    .println("if you had installed the JMF but did not run JMFRegistry, please run JMFRegistry and try again");
            System.out
                    .println("It is in the same folder as JMStudio in applications menu");
        } else if (deviceList.size() == 1) {
            ml = ((CaptureDeviceInfo) deviceList.get(0)).getLocator();
        } else {
            System.out
                    .println("There are more than one Video device on this machine.");
            System.out.println("We will try the first one");
            ml = ((CaptureDeviceInfo) deviceList.get(0)).getLocator();
        }
        return ml;
    }

    // HG: Added for security init
    private String topicName = "encrypted";
    private String topicUUID;
    private PrivateKey c1_priv;
    private String algo = null;
    private int keylen = -1;

    private EventProducer producer;

    SecureTopicKeyResponse resp;

}
